package com.puzzlebazar.client.util;

import java.util.Vector;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.HasAllKeyHandlers;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;

public class LabeledFieldImpl implements LabeledField, HasAllKeyHandlers  {

	protected final Label label ;
	protected final TextBox textBox;

	private final Label errorLabel = new Label();
	private boolean error = false;
	
	private final Vector<ValidationCallback> validationCallbacks = new Vector<ValidationCallback>();
	private final Vector<ChangeHandler> changeHandlers = new Vector<ChangeHandler>();
	

	/**
	 * Creates a labeled field with the specified label and a specific text box
	 * 
	 * @param textBox The textbox to use
	 * @param labelText The text to put in the label
	 * @param maxLength The maximum length of the content in the textbox
	 * @param filter The filter to use on this input (can be null for no filtering)
	 */
	protected LabeledFieldImpl( TextBox textBox, String labelText, int maxLength, BasicFilter filter ) {
		this.textBox = textBox;
		label = new Label( labelText );	
		initialize(maxLength, filter);
	
	}
	
	/**
	 * Creates a labeled field with the specified label
	 * 
	 * @param labelText The text to put in the label
	 * @param maxLength The maximum length of the content in the textbox
	 * @param filter The filter to use on this input (can be null for no filtering)
	 */
	public LabeledFieldImpl( String labelText, int maxLength, BasicFilter filter ) {
		textBox = new TextBox();
		label = new Label( labelText );	
		initialize(maxLength, filter);
	
	}

	/**
	 * Initialize the field, should only be called by the constructor
	 * 
	 * @param maxLength The maximum length of the content in the textbox
	 * @param filter The filter to use on this input (can be null for no filtering)
	 */
	private void initialize(int maxLength, BasicFilter filter) {
		label.setStylePrimaryName( "entryLabel" );
		textBox.setWidth( "100%" );
		textBox.setMaxLength(maxLength );
		if( filter != null )
			textBox.addKeyPressHandler( filter );

		MyChangeHandler myKeyboardHandler = new MyChangeHandler();
		myKeyboardHandler.addToWidget(textBox);
					
		errorLabel.setStylePrimaryName( "errorLabel" );
	}
	
	@Override
	public void resetError() {
		errorLabel.setText( "" );
		error = false;
	}
	
	@Override
	public void setError( String errorText ) {
		errorLabel.setText( errorText );
		error = true;
	}

	@Override
	public boolean hasError() {
		return error;
	}

	@Override
	public String getEntry() {
		return textBox.getText();
	}

	@Override
	public void setEntry( String entryText ) {
		textBox.setText( entryText );
		validate();
	}
	
	
	@Override
	public void addToGrid( Grid grid, int row ) {		

		grid.setWidget( row, 0, label );
		grid.setWidget( row, 1, textBox );
		grid.setWidget( row, 2, errorLabel );

	}
	
	@Override
	public void addValidationCallback( ValidationCallback callback ) {
		validationCallbacks.add( callback );
		if( !error ) {
			String error = callback.validate(getEntry());
			if( error != null )
				setError( error );
		}
	}

	@Override
	public void addChangeHandler( ChangeHandler handler ) {
		changeHandlers.add( handler );
		handler.onChange(null);
	}

	@Override
	public void validate() {
	
		String entry = getEntry();
		String error = null;
		for (ValidationCallback callback : validationCallbacks ) {
			error = callback.validate(entry);
			if( error != null ) break;
		}
		if( error != null ) 
			setError( error );
		else
			resetError();

		for (ChangeHandler handler : changeHandlers ) {
			handler.onChange(null);
		}
	}

	@Override
	public int getTabIndex() {
		return textBox.getTabIndex();
	}

	@Override
	public void setAccessKey(char key) {
		textBox.setAccessKey(key);		
	}

	@Override
	public void setFocus(boolean focused) {
		textBox.setFocus(focused);		
	}
	
	@Override
	public void setTabIndex(int index) {
		textBox.setTabIndex(index);		
	}

	private class MyChangeHandler extends InstantChangeHandler {
		@Override
		public void onChange(ChangeEvent event) {
			validate();
		}
	}

	@Override
	public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
		return textBox.addKeyUpHandler(handler);
	}

	@Override
	public void fireEvent(GwtEvent<?> event) {
		textBox.fireEvent(event);
		
	}

	@Override
	public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
		return textBox.addKeyDownHandler(handler);
	}

	@Override
	public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
		return textBox.addKeyPressHandler(handler);
	}
}
